home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_100
/
188_01
/
trans.c
< prev
next >
Wrap
Text File
|
1987-09-29
|
7KB
|
217 lines
/*
HEADER: ;
TITLE: C elementary transcendentals;
VERSION: 1.0;
DESCRIPTION: Source code for all standard C
transcendentals
Employs ldexp() and frexp() functions; if
suitable versions of these are not provided
by a given compiler, the versions provided in
source code will require adaptation to the
double float formats of the compiler.
KEYWORDS: Transcendentals, library;
SYSTEM: CP/M-80, V3.1;
FILENAME: TRANS.C;
WARNINGS: frexp() and ldexp() are implementation
dependent. The compiler employed does not
support minus (-) unary operators in
initializer lists, which are required by the
code.
AUTHORS: Tim Prince;
COMPILERS: MIX C, v2.0.1;
*/
/* Copyright (C) 1986, Chandler Software,
** 4456 W. Maple Rd., Birmingham MI 48010-1923
** (313) 855-4587
** C adaptation of 1984 FORTRAN code
** prepared for non-profit distribution by C Users' Group */
/*$NESTCMNT*/
# include "a:stdio"
/* dblfmt describes floating point format
** machine dependencies in case frexp() and ldexp() are not
** supplied */
union dblfmt{
double flt;
struct{
char mant[7]; /* full reverse byte order
** IEEE int sign:1;unsigned expn:11;unsigned mant:4
** with DEC reverse byte pairing, can't cross 16-bit
** boundaries */
char expn;
}fld; /* char same as unsigned :8 in this C */
}
#define ROUND(x) (int)((x>=0)-.5+x) /* Pascal ROUND */
#define ODD(i) ((i)&1) /* also like Pascal */
/* teach the preprocessor some algebra */
#define PI 3.1415926535897932385
#define HPI 1.5707963267948966192
#define LN2 .69314718055994530942
#define L2E 1.442695040888963407
#define cos(x) sin(HPI-(x)) /* double sin() */
#define tan(x) sin(x)/cos(x) /* double sin() */
/* for future use
#define fabs(x) (x>=0?x:-(x))
/* double sin() */
#define atan2(x,y) (y>0?atan((x)/(y)):y==0?(x>=0?HPI:-HPI):(x>=0?PI+atan((x)/(y)):atan((x)/(y))-PI))
#define asin(x) atan2(x,sqrt((1-(x))*(1+x))) /* double sin(),sqrt() */
#define acos(x) atan2(sqrt((1-(x))*(1+x)),x) /* double sin(),sqrt() */
#define log(x) log2(x)*LN2 /* double log2() */
#define exp(x) exp2((x)*L2E) /* double exp2() */
#define cosh(x) sqrt(sinh(x)*sinh(x)+1) /* double sinh(),sqrt() */
#define tanh(x) (x<-20?-1.:(x>=20?1.:sinh(x)/cosh(x)))
*/
#define pow(x,y) exp2(log2(x)*(y))
main(){ /* test accuracy of tan,sin,cos,atan,exp2,log2 */
double sin(),atan(),log2(),exp2();
double x;
for(x=1e-36;x<1e33;x*=1e4)
printf("x:%23.16e tan(atan):%23.16e \n\tpow:%23.16e\n",
x,tan(atan(x)),pow(x,1.));
}
double frexp(x,scale)
int *scale;
double x;
{
union dblfmt x1;
#define BIAS 128 /* exponent field of .9 (IEEE 1023) */
x1.flt=x;
*scale=x1.fld.expn-BIAS; /* scale by .5^(*scale) */
x1.fld.expn=BIAS; /* .5 <= result < 1 */
return(x1.flt);
}
double ldexp(x,scale)
double x;
int scale;
{
union dblfmt x1;
x1.flt=x;
/* scale by 2^scale */
x1.fld.expn+=scale;
return(x1.flt);
}
double sin(x)
double x;
{
#define NTS 8
/* negative signs are ignored by some compilers! */
static double table[NTS]={
-.7370812e-12,.160478576e-9,-.2505187133e-7,
.275573164289e-5,-.00019841269823293,
.008333333333276252,-.1666666666666597,.9999999999999999};
double poly(),pm,floor();
/* try to take care of x>maxint unless much too slow
** employ periodicity sin(x+n*PI)=(-1)^n*sin(x) */
x-=PI*(pm=floor(x/PI+.5));
/* now |x| < HPI; use series and fix sign */
return(poly(x*x,NTS,table)*(ODD((int)pm)?-x:x));
}
/* use fast polynomial evaluation (possibly non-portable) */
double poly(x,n,table)
double x;
int n;
double table[];
{
register double sum;
register int i;
sum=table[0];
/* unroll loop by pairing terms to save overhead */
for(i=2;i<n;i+=2)
sum=(sum*x+table[i-1])*x+table[i];
return(i==n?sum*x+table[i-1]:sum);
}
double atan(x)
double x;
{
#define TNPI6 .57735026918962576451
#define NTA 9
static double table[NTA]={
.0443911883527,-.06483241134718,.07679374240257,
-.090903714847573,.111110979102203,-.1428571410307564,
.1999999999873222,-.33333333333329944,
.99999999999999999};
char invert,reduce,neg;
double poly();
/* atan(-x)=-atan(x) */
if(neg=(x<0))x=-x;
/* tan(HPI-x)=1/tan(x) */
if(invert=(x>=1))x=1/x;
/* tan(a-b)={tan(a)-tan(b)}/{tan(a)*tan(b)+1}; b=PI/6 */
if(reduce=(x>=.269))x=(x-TNPI6)/(x*TNPI6+1);
x*=poly(x*x,NTA,table);
if(reduce)x+=.52359877559829887308;
if(invert)x=HPI-x;
return(neg?-x:x);
}
double log2(x)
double x;
{
#define NTL 7
static double table[NTL]={
.24291838162,.2614440423316,.3206163946133,.41219840197457,
.57707801724629,.961796693924339,2.885390081777927};
int scale,incsc;
double poly(),ldexp(),frexp();
/* split x -> 2^scale*(reduced x near 1) */
incsc=frexp(x,&scale)<.7071;
x=ldexp(x,-(scale-=incsc));
x=(x-1)/(x+1);
return(poly(x*x,NTL,table)*x+scale);
}
double exp2(x)
double x;
{
#define INFINITY 1.7e38/*IEEE 0x7ff0000000000000*/
#define MAXEXP 127 /* IEEE 1023 */
#define MINLG2 -128
double evenp,oddp,xsq,ldexp();
int scale;
if(x>=MAXEXP)return(INFINITY);
if(x<MINLG2)return(0);
/* 2^x=2^ROUND(x)*2^(x-ROUND(x)) */
x-=scale=ROUND(x);
/* approximation is ratio of polynomials differing only in
** sign of odd terms */
xsq=x*x;
/* continued fraction approx for e^x
(x*(15120+xsq*(420+xsq))+30240+xsq*(3360+xsq*30))/... */
/* minimax fit for 2^x, 18 significant digits */
oddp=x*(65556.325877407443+xsq*(874.804294426022+xsq));
evenp=189155.572484473087+xsq*(10097.515376265486+
xsq*43.302654542155);
return(ldexp((evenp+oddp)/(evenp-oddp),scale));
}
/* for future use
double sinh(x)
double x;
{
#define NTSH 7
static double table[NTSH]={
1.632721e-10,2.50484370e-8,2.7557344083e-6,
1.984126975507e-4,.0083333333334753,.1666666666666579,
1.0000000000000001};
double poly(),exp2();
return(fabs(x)<1?poly(x*x,NTSH,table)*x:(exp(x)-1/exp(x))/2);
}
double sqrt(x) /* as if division hardware but no sqrt */
double x;
{ static float table[]={.59,.417,.295}; /* minimax 2 digits */
register double x1;
double frexp(),ldexp();
register int i;
register char iters=3; /* number of Newton iterations */
register float x0; /* early stages need 2.5 digits precision */
int scale;
if(x<=0)return(x);
x0=frexp(x,&scale); /* sqrt(2^x*y)=2^(x/2)sqrt(y) */
i=ODD(scale); /* separate fits for y<.5 & y>.5 */
x1=ldexp(x0*table[i]+table[i+1],(scale+1)>>1); /*crude sqrt*/
do /* enough Newton iterations for full accuracy */
x1=ldexp(x/x1+x1,-1); /* ldexp might be faster than *.5 */
while(--iters);
return(x1);
}
*/